/**
 * @class UI-面板-镜头设置面板
 * @author DuskyHuang
 * @description 甚至关于所有镜头的配置。
 */

import { _decorator, Toggle, Slider, Node, Label, BlockInputEvents, Sprite, Color } from 'cc';
import { Res } from 'const';
import { Mediator } from 'cfw';
import { UI } from 'notifications';
import { changeFrame } from 'helpers';
import { ui } from 'proxies';
const { ccclass, property } = _decorator;


@ccclass('cocosmos.lens-panel')
export class LensPanel extends Mediator {

    @property(Toggle) public autoHover: Toggle = null;
    @property(Toggle) public autoPitch: Toggle = null;
    @property(Toggle) public autoZoom: Toggle = null;
    @property(Toggle) public lensLock: Toggle = null;
    @property(Toggle) public showLensVel: Toggle = null;
    @property(Toggle) public showEscVel: Toggle = null;
    @property(Toggle) public showCivLvl: Toggle = null;
    @property(Slider) public azSlider: Slider = null;
    @property(Slider) public haSlider: Slider = null;
    @property(Slider) public haMinSlider: Slider = null;
    @property(Slider) public haMaxSlider: Slider = null;
    @property(Slider) public zoomSlider: Slider = null;

    @property(Sprite) public title: Sprite = null;
    @property(Sprite) public confirm: Sprite = null;
    @property(Sprite) public cancel: Sprite = null;

    @property(Node) public content: Node = null;

    protected onLoad(): void { this._init(); }
    protected onEnable(): void { this.changeSpriteLang(); }

    protected start(): void { this._setDefaults(); }

    private _init(): void {
        this.content.children.forEach(line => {
            const toggle = line.getComponentInChildren(Toggle);
            this._lines.set(line, {
                toggle,
                unchecked: toggle.getComponent(Sprite),
                titles: toggle.getComponentsInChildren(Label),
                sliders: line.getComponentsInChildren(Slider),
                block: line.getComponentInChildren(BlockInputEvents) ?? null,
            });
        });
        this.content.getComponentsInChildren(Slider).forEach(slider => {
            this._sliders.set(slider, {
                bar: slider.node.getChildByName('Bar').getComponent(Sprite),
                sprites: slider.getComponentsInChildren(Sprite),
                value: slider.getComponentInChildren(Label),
                range: Ranges[slider.node.name]
            });
        });
    }

    private _setDefaults(): void {
        this.content.getComponentsInChildren(Toggle).forEach(toggle => {
            if (toggle.node.name !== 'Toggle') {
                toggle.setIsCheckedWithoutNotify(ui.getStateByName(toggle.node.name));
                toggle.node.name += ':check';
            }
        });
        this.content.getComponentsInChildren(Toggle).forEach(toggle => this.toggleUsage(toggle));
        this.content.getComponentsInChildren(Slider).forEach(slider => {
            slider.progress = this._sliders.get(slider).range[3];
            this.slideDegree(slider);
        });
        this.changeSpriteLang();
    }

    protected changeSpriteLang(): void {
        const { language } = ui, POPS = Res.Sheets.UI_POPS, en = language === 'en';
        changeFrame(this.title, POPS, 'en', en);
        changeFrame(this.confirm, POPS, 'en', en);
        changeFrame(this.cancel, POPS, 'en', en);
    }

    protected toggleUsage(tgl: Toggle): void {
        const checked = tgl.isChecked;
        const line = tgl.node.parent;
        const { unchecked, titles, sliders, block } = this._lines.get(line);
        unchecked.enabled = !checked;
        titles.forEach(title => title.color = checked ? Color.WHITE : Color.GRAY);
        sliders.forEach(slider => {
            const { sprites, value } = this._sliders.get(slider);
            sprites.forEach(sprite => changeFrame(sprite, Res.Sheets.UI_POPS, 'dis', !checked));
            value.color = checked ? Color.WHITE : Color.GRAY;
        });
        if (block) block.enabled = !checked;
    }

    protected slideDegree(slider: Slider): void {
        const { bar, value, range: [, , unit] } = this._sliders.get(slider);
        const v = Math.round(this._getValue(slider));
        value.string = (v >= 0 ? '+' : '') + v.toFixed(0) + unit;
        bar.fillRange = slider.progress;
    }

    private _getValue(slider: Slider): number {
        const [min, max,] = Ranges[slider.node.name];
        return Math.lerp(min, max, slider.progress);
    }

    protected onApply(): void {
        const params: LensPanelParams = {
            hover: this.autoHover.isChecked,
            pitch: this.autoPitch.isChecked,
            zoom: this.autoZoom.isChecked,
            lock: this.lensLock.isChecked,
            showLensVel: this.showLensVel.isChecked,
            showEscVel: this.showEscVel.isChecked,
            showCivLvl: this.showCivLvl.isChecked,
        };
        if (params.hover) params.az = this._getValue(this.azSlider);
        if (params.pitch) {
            params.ha = this._getValue(this.haSlider);
            params.haRange = [this._getValue(this.haMinSlider), this._getValue(this.haMaxSlider)];
        }
        if (params.zoom) params.pow10 = this._getValue(this.zoomSlider) / 100;
        this.notify(UI.LENS_PARAMS, params);
        this.notify(UI.Panels.CLOSE, this.node.name);
    }

    protected onClose(): void {
        this.notify(UI.Panels.CLOSE, this.node.name);
    }

    protected onHide(): void {
        this.node.removeFromParent();
    }

    private _lines: Map<Node, lineContent> = new Map;
    private _sliders: Map<Slider, slider> = new Map;
}

declare type lineContent = { toggle: Toggle, unchecked: Sprite, titles: Label[], sliders: Slider[], block?: BlockInputEvents };

declare type slider = { bar: Sprite, sprites: Sprite[], value: Label, range: range };

declare type range = [min: number, max: number, unit: string, dft: number]

const Ranges: Dictionary<range> = {
    ['旋转']: [-180, 180, '°/s', 0.5],
    ['推拉']: [-50, 50, 'x0.01/s', 0.5],
    ['俯仰']: [-30, 30, '°/s', 0.5],
    ['最高']: [-80, 80, '°', 0.7],
    ['最低']: [-80, 80, '°', 0.4],
}